package com.bonshotels;

import java.text.DateFormat;
import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.bonshotels.DataLayer.Hibernate.HibernateUtil;
import com.bonshotels.DomainLayer.DomainControllers.CUReservarHabitacio;
import com.bonshotels.DomainLayer.DomainModel.CategoriaHotel;
import com.bonshotels.DomainLayer.DomainModel.Client;
import com.bonshotels.DomainLayer.DomainModel.DescompteFixe;
import com.bonshotels.DomainLayer.DomainModel.DescompteVariable;
import com.bonshotels.DomainLayer.DomainModel.Habitacio;
import com.bonshotels.DomainLayer.DomainModel.Hotel;
import com.bonshotels.DomainLayer.DomainModel.Poblacio;
import com.bonshotels.DomainLayer.DomainModel.PreuTipusHabitacio;
import com.bonshotels.DomainLayer.DomainModel.Reserva;
import com.bonshotels.DomainLayer.DomainModel.SenseDescompte;
import com.bonshotels.DomainLayer.DomainModel.TipusHabitacio;
import com.bonshotels.Excepcions.ClientNoExisteix;
import com.bonshotels.Excepcions.HabitacioNoExisteix;
import com.bonshotels.Excepcions.HotelNoExisteix;
import com.bonshotels.Excepcions.HotelsNoDisp;
import com.bonshotels.Excepcions.NoHiHaPoblacions;
import com.bonshotels.Excepcions.PoblacioNoExisteix;
import com.bonshotels.Excepcions.ServeiNoDisponible;

public class MainHibernateBonsHotels {
	
	/**
	 * @param args
	 * @throws HabitacioNoExisteix 
	 * @throws ClientNoExisteix 
	 * @throws ServeiNoDisponible 
	 * @throws PoblacioNoExisteix 
	 * @throws HotelNoExisteix 
	 * @throws NoHiHaPoblacions 
	 */
	public static void main(String[] args) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			
			Scanner sc = new Scanner(System.in);
			System.out.println("Vols poblar la BD amb el joc de proves? (Si/No)");
			String pobla = sc.nextLine();
			if (pobla == "Si") {
				//insereix poblacions
		        Poblacio p1 = new Poblacio();
		        p1.setNom("Barcelona");
		        session.save(p1);
		        Poblacio p2 = new Poblacio();
		        p2.setNom("Tarragona");
		        session.save(p2);
		        Poblacio p3 = new Poblacio();
		        p3.setNom("Sant Jaume de Frontanya");
		        session.save(p3);
		        
		      //insereix categoria hotel
		        CategoriaHotel ch = new CategoriaHotel();
		        ch.setNom("GrandResort"); 
		        session.save(ch);
		        
		        //insereix tipus habitacio
		        TipusHabitacio tipus1 = new TipusHabitacio();        
		        tipus1.setNom("Suit reial");
		        tipus1.setCapacitat(6);
		        tipus1.setDescripcio("Si ets pobre, millor ni miris.");        
		        session.persist(tipus1);        
		        TipusHabitacio tipus2 = new TipusHabitacio();
		        tipus2.setNom("Habitacio doble");
		        tipus2.setCapacitat(2);
		        tipus2.setDescripcio("Si ets ric, millor ni miris.");        
		        session.persist(tipus2);
		        
		        
		        Set<Hotel> hotels1 = new HashSet<Hotel>();
		        Hotel h1 = new Hotel();
		        h1.setNom("Princess");
		        h1.setDescripcio("lalalala");
		        h1.setCategoriaHotel(ch);
		        hotels1.add(h1);
		        Hotel h2 = new Hotel();
		        h2.setNom("Juan Carlos");
		        h2.setDescripcio("lalalala");
		        h2.setCategoriaHotel(ch);
		        hotels1.add(h2);
		        p1.setHotel(hotels1);
		        session.save(h1);
		        session.save(h2);
		        session.save(p1);
		        
		        Set<Hotel> hotels2 = new HashSet<Hotel>();
		        Hotel h3 = new Hotel();
		        h3.setNom("Migdia");
		        h3.setDescripcio("lalalala");
		        h3.setCategoriaHotel(ch);
		        hotels2.add(h3);
		        Hotel h4 = new Hotel();
		        h4.setNom("Aprovarem");
		        h4.setDescripcio("lalalala");
		        h4.setCategoriaHotel(ch);
		        hotels2.add(h4);
		        p2.setHotel(hotels2);
		        session.save(h3);
		        session.save(h4);
		        session.save(p2);
		        
		        SenseDescompte sd1 = new SenseDescompte();
		        session.save(sd1);
		        DescompteFixe df1 = new DescompteFixe();
		        df1.setDescompteFixe(1);
		        session.save(df1);
		        DescompteVariable dv1 = new DescompteVariable();
		        dv1.setDescompteVariable(1);
		        session.save(dv1);
		        
		        Set<PreuTipusHabitacio> pthHotel1 = new HashSet<PreuTipusHabitacio>();
				
				PreuTipusHabitacio pth1 = new PreuTipusHabitacio();
				pth1.setPreu(6);
				pth1.setiECP(sd1);
				pth1.settH(tipus1);
				pth1.setHotel(h1);
				pthHotel1.add(pth1);
				session.save(pth1);
				
				
				PreuTipusHabitacio pth2 = new PreuTipusHabitacio();
				pth2.setPreu(7);
				pth2.setiECP(df1);
				pth2.settH(tipus2);
				pth2.setHotel(h1);
				pthHotel1.add(pth2);
				session.save(pth2);
				
				h1.setPreuTipusHabitacio(pthHotel1);
				session.update(h1);
				
				Set<PreuTipusHabitacio> pthHotel2 = new HashSet<PreuTipusHabitacio>();
				
				PreuTipusHabitacio pth3 = new PreuTipusHabitacio();
				pth3.setPreu(6);
				pth3.setiECP(dv1);
				pth3.settH(tipus1);
				pth3.setHotel(h2);
				pthHotel2.add(pth3);
				session.save(pth3);
				
				PreuTipusHabitacio pth4 = new PreuTipusHabitacio();
				pth4.setPreu(7);
				pth4.setiECP(sd1);
				pth4.settH(tipus2);
				pth4.setHotel(h2);
				pthHotel2.add(pth4);
				session.save(pth4);
				
				h2.setPreuTipusHabitacio(pthHotel2);
				session.update(h2);
				
				Set<PreuTipusHabitacio> pthHotel3 = new HashSet<PreuTipusHabitacio>();
				
				PreuTipusHabitacio pth5 = new PreuTipusHabitacio();
				pth5.setPreu(7);
				pth5.setiECP(df1);
				pth5.settH(tipus1);
				pth5.setHotel(h3);
				pthHotel3.add(pth5);
				session.save(pth5);
				
				PreuTipusHabitacio pth6 = new PreuTipusHabitacio();
				pth6.setPreu(6);
				pth6.setiECP(dv1);
				pth6.settH(tipus2);
				pth6.setHotel(h3);
				pthHotel3.add(pth6);
				session.save(pth6);
				
				h3.setPreuTipusHabitacio(pthHotel3);
				session.update(h3);
				
				Set<PreuTipusHabitacio> pthHotel4 = new HashSet<PreuTipusHabitacio>();
				
				PreuTipusHabitacio pth7 = new PreuTipusHabitacio();
				pth7.setPreu(7);
				pth7.setiECP(sd1);
				pth7.settH(tipus1);
				pth7.setHotel(h4);
				pthHotel4.add(pth7);
				session.save(pth7);
				
				
				
				PreuTipusHabitacio pth8 = new PreuTipusHabitacio();
				pth8.setPreu(6);
				pth8.setiECP(df1);
				pth8.settH(tipus2);
				pth8.setHotel(h4);
				pthHotel4.add(pth8);
				session.save(pth8);
				
				h4.setPreuTipusHabitacio(pthHotel4);
				session.update(h4);
				
				Set<Habitacio> habHotel1 = new HashSet<Habitacio>();
				
				Habitacio hab1 = new Habitacio();
				hab1.setNumero(1);
				hab1.setTipusHabitacio(tipus1);
				hab1.setHotel(h1);
				habHotel1.add(hab1);
				session.save(hab1);
		
				Habitacio hab2 = new Habitacio();
				hab2.setNumero(2);
				hab2.setTipusHabitacio(tipus1);
				hab2.setHotel(h1);
				habHotel1.add(hab2);
				session.save(hab2);
						
				Habitacio hab3 = new Habitacio();
				hab3.setNumero(3);
				hab3.setTipusHabitacio(tipus2);
				hab3.setHotel(h1);
				habHotel1.add(hab3);
				session.save(hab3);
				
				h1.setHabitacio(habHotel1);
				session.update(h1);
				
				Set<Habitacio> habHotel2 = new HashSet<Habitacio>();
				
				Habitacio hab4 = new Habitacio();
				hab4.setNumero(1);
				hab4.setTipusHabitacio(tipus1);
				hab4.setHotel(h2);
				habHotel2.add(hab4);
				session.save(hab4);
		
				Habitacio hab5 = new Habitacio();
				hab5.setNumero(2);
				hab5.setTipusHabitacio(tipus1);
				hab5.setHotel(h2);
				habHotel2.add(hab5);
				session.save(hab5);
						
				Habitacio hab6 = new Habitacio();
				hab6.setNumero(3);
				hab6.setTipusHabitacio(tipus2);
				hab6.setHotel(h2);
				habHotel2.add(hab6);
				session.save(hab6);
				
				h2.setHabitacio(habHotel2);
				session.update(h2);
				
				Set<Habitacio> habHotel3 = new HashSet<Habitacio>();
				
				Habitacio hab7 = new Habitacio();
				hab7.setNumero(1);
				hab7.setTipusHabitacio(tipus1);
				hab7.setHotel(h3);
				habHotel3.add(hab7);
				session.save(hab7);
		
				Habitacio hab8 = new Habitacio();
				hab8.setNumero(2);
				hab8.setTipusHabitacio(tipus1);
				hab8.setHotel(h3);
				habHotel3.add(hab8);
				session.save(hab8);
				
				h3.setHabitacio(habHotel3);
				session.update(h3);
				
				//clients
				Client c1 = new Client();
				c1.setNom("Marc");
				c1.setCognoms("Mauri");
				c1.setDni("dni1");
				c1.setEmail("senyorpatrons@aprovarem.net");
				session.save(c1);
				
				Client c2 = new Client();
				c2.setNom("Ana");
				c2.setCognoms("Rebollo");
				c2.setDni("dni2");
				c2.setEmail("senyoratincgana@potsersipotserno.net");
				session.save(c2);
				
				Client c3 = new Client();
				c3.setNom("Jordi");
				c3.setCognoms("Sabater");
				c3.setDni("dni3");
				c3.setEmail("senyorsuspendrem@suspendrem.net");
				session.save(c3);
		        
			}
			
//#############################################################################################			
	       
			CUReservarHabitacio cURH = new CUReservarHabitacio();  
	        boolean sortir = false;	      
			int op = 0;
	        while(!sortir) {
		        switch(op) {
		        	case 0:
				        try {
							poblacions = cURH.obtePoblacions();
							System.out.println("[Pas1]Escull la poblacio en la que vols buscar hotel.");
							System.out.println("[Pas1]Per a escollir una poblacio escriu el seu numero associat.");
							Integer comptador = 0;
							for(String s : poblacions) {
								System.out.println(comptador.toString() + " " + s);
								++comptador;
							}
							boolean correcte = false;
							while(!correcte) {
								Scanner scanner = new Scanner(System.in);
								String entrada = scanner.nextLine();
								try {
									int escollit = Integer.parseInt(entrada);
									if(escollit >= comptador || escollit < 0) throw new Exception();
									correcte = true;
									int aux = 0;
									Iterator<String> pob = poblacions.iterator();
									while(aux < escollit) {
										pob.next();
										++aux;
									}
									poblacio = pob.next();
									op = 1;
								} catch(Exception e) {
									System.out.println("Lopcio escollida no coincideix amb cap de la llista.");
								}
							}
						} catch (NoHiHaPoblacions e) {
							System.out.println("[Error]" + e.getMessage());
							System.out.println("[Consell]Contacteu el vostre administrador.");
							sortir = true;
						}
				        break;
		        	case 1:
		        		System.out.println("[Pas2]Introdueix la data d'arribada amb el format dd/mm/aaaa.");
		        		boolean correcte = false;
		        		while(!correcte) {
							Scanner scanner = new Scanner(System.in);
							String entrada = scanner.nextLine();	
							SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
							try {
								dIni = sdf.parse(entrada);
								correcte = true;
							} catch (ParseException e) {
								System.out.println("[Error]La data no segueix el format dd/mm/aaaa.");
							}
		        		}
		        		correcte = false;
		        		System.out.println("[Pas3]Introdueix la data de sortida amb el format dd/mm/aaaa.");
		        		while(!correcte) {
							Scanner scanner = new Scanner(System.in);
							String entrada = scanner.nextLine();	
							SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
							try {
								dFi = sdf.parse(entrada);
								correcte = true;
							} catch (ParseException e) {
								System.out.println("[Error]La data no segueix el format dd/mm/aaaa.");
							}
		        		}
		        		correcte = false;
		        		System.out.println("[Pas4]Introdueix el numero docupants per la reserva.");
						while(!correcte) {
							Scanner scanner = new Scanner(System.in);
							String entrada = scanner.nextLine();
							try {
								numOcup = Integer.parseInt(entrada);
								if(numOcup < 1) throw new Exception();
								correcte = true;
								op = 2;
							} catch(Exception e) {
								System.out.println("El que has introduit no es un numero valid. Ha de ser un enter estrictament positiu.");
							}
						}
		        		break;
		        	case 2:
		        		if(dIni.before(dFi) && !((dIni.getDate() == dFi.getDate()) && 
		        		  (dIni.getMonth() == dFi.getMonth()) && (dIni.getYear() == dFi.getYear()))) {
							try {
								Set<Map<String, Object>> habsHots = cURH.buscarHabitacio(poblacio, dIni, dFi, numOcup);
								System.out.println("[Pas5]Escull un hotel de la llista tot escrivint el seu numero associat.");
								System.out.println("[Pas5]Per cada hotel pots observar la seva categoria, avaluacio i descripcio.");
								System.out.println("[Pas5]Cada hotel te uns tipus dhabitacio disponibles, de cada un sinforma del seu nom, numero disponible i preu.");
								Integer comptador = 0;
								for(Map<String, Object> hotels : habsHots) {
									String sortida = comptador.toString() + " ";
									sortida = sortida + (String) hotels.get("nomHotel");
									sortida = sortida + " " + (String) hotels.get("categoria");
									sortida = sortida + " " + ((Float) hotels.get("avaluacio")).toString();
									System.out.println(sortida);
									System.out.println((String)hotels.get("desc"));
									Set<Map<String, Object> > habs = (Set<Map<String, Object>>) hotels.get("habs");
									for(Map<String, Object> hab : habs) {
										String tipusHab = "--->" + (String)hab.get("tipusHab");
										tipusHab = " " + tipusHab + " " + ((Integer)hab.get("numeroDisp")).toString();
										tipusHab = " " + tipusHab + " " + ((Float)hab.get("preu")).toString();
										System.out.println(tipusHab);
									}
									++comptador;
								}

								boolean correcte2 = false;
								while(!correcte2) {
									Scanner scanner = new Scanner(System.in);
									String entrada = scanner.nextLine();
									try {
										int escollit = Integer.parseInt(entrada);
										if(escollit >= comptador || escollit < 0) throw new Exception();
										correcte2 = true;
										int aux = 0;
										Iterator<Map<String, Object>> hots = habsHots.iterator();
										while(aux < escollit) {
											hots.next();
											++aux;
										}
										hotel = hots.next();
										op = 3;
										
									} catch(Exception e) {
										System.out.println("Lopcio escollida no coincideix amb cap de la llista.");
									}
								}

							} catch (HotelsNoDisp e) {
								System.out.println("[Error]" + e.getMessage());
								op = 0;
							} catch (PoblacioNoExisteix e) {
								System.out.println("[Error]" + e.getMessage());
								op = 0;
							}
		        		}
		        		else {
							System.out.println("[Error]La data d'arribada es posterior o igual a la de sortida");
							System.out.println("[Consell]Modifiqui-les de manera que aixo no passi");
							op = 1;
		        		}
		        		break;
		        	case 3:
		        		System.out.println("[Pas6]Escull un tipus dhabitacio del hotel, de cada tipus sinforma del seu nom, numero disponible i preu.");
		        		Integer comptador = 0;
		        		Set<Map<String, Object> > hot = (Set<Map<String, Object> >) hotel.get("habs");
						for(Map<String, Object> hab : hot) {
							String tipusHab = comptador.toString() + " " + (String)hab.get("tipusHab");
							tipusHab = " " + tipusHab + " " + ((Integer)hab.get("numeroDisp")).toString();
							tipusHab = " " + tipusHab + " " + ((Float)hab.get("preu")).toString();
							System.out.println(tipusHab);
							++comptador;
						}
						
						boolean correcte2 = false;
						while(!correcte2) {
							Scanner scanner = new Scanner(System.in);
							String entrada = scanner.nextLine();
							try {
								int escollit = Integer.parseInt(entrada);
								if(escollit >= comptador || escollit < 0) throw new Exception();
								correcte2 = true;
								int aux = 0;
								Iterator<Map<String, Object> > habi = hot.iterator();
								while(aux < escollit) {
									habi.next();
									++aux;
								}
								tipusHab = (String) habi.next().get("tipusHab");
								nomHotel = (String) hotel.get("nomHotel");
								op = 4;
							} catch(Exception e) {
								System.out.println("Lopcio escollida no coincideix amb cap de la llista.");
							}
						}
						break;
						
		        	case 4:
					try {
						Map<String,Object> dadesReserva = cURH.selecionarHabitacio(nomHotel, tipusHab);
						Format formatter;
						formatter = new SimpleDateFormat("dd/MM/yy");
						String dataINI = formatter.format((Date)dadesReserva.get("dIni"));
						String dataFI = formatter.format((Date)dadesReserva.get("dFi"));
						System.out.println("[Pas7]Comprova que les dades de la reserva son correctes i a continuacio introdueix el DNI.");
						System.out.println("--->Poblacio: " + (String)dadesReserva.get("pob"));
						System.out.println("--->Data darribada: " + dataINI);
						System.out.println("--->Data de sortida: " + dataFI);
						System.out.println("--->Hotel: " + (String)dadesReserva.get("hotel"));
						System.out.println("--->Tipus dhabitacio: " + (String)dadesReserva.get("tipusHab"));
						System.out.println("--->Preu total: " + ((Float)dadesReserva.get("preuTotal")).toString());
						System.out.println("[Pas7]Si son correctes escriu el DNI, si no ho son escriu 0 per tornar a fer la reserva.");
						
						Scanner scanner = new Scanner(System.in);
						dni = scanner.nextLine();
						int escollit = -1;
						try {
							escollit = Integer.parseInt(dni);
							if(escollit == 0) op = 0;
							else op = 5;
						} catch (NumberFormatException e) {
							op = 5;
						} 
						
					} catch (HotelNoExisteix e) {
						System.out.println("[Error]" + e.getMessage());
						op = 1;						
					}
		        		break;
		        	case 5:
					try {
						Map<String,Object> habClient = cURH.introduirDni(dni);
						System.out.println("[Pas8]Comprova que les dades de client son correctes i introduix els camps demanats per a poder procedir amb el pagament.");
						System.out.println("--->DNI: " + (String)habClient.get("dni"));
						System.out.println("--->Nom: " + (String)habClient.get("nom"));
						System.out.println("--->Cognoms: " + (String)habClient.get("cognoms"));
						System.out.println("--->Email: " + (String)habClient.get("email"));
						System.out.println("[Pas8]Si son correctes escriu el numero de tarja, si no ho son escriu 0 per tornar a introduir el DNI.");
						Scanner scanner = new Scanner(System.in);
						targeta = scanner.nextLine();
						int tarja = -1;
						try {
							tarja = Integer.parseInt(targeta);
							if(tarja == 0) op = 4;
							else op = 6;
						} catch (NumberFormatException e) {
							op = 6;
						} 
						System.out.println("[Pas8]A continuacio introdueix la data de caducitat de la tarja en format mm/aaaa.");

		        		boolean correcte3 = false;
		        		while(!correcte3 && op == 6) {
							String dataCaducitat = scanner.nextLine();	
							SimpleDateFormat sdf = new SimpleDateFormat("MM/yyyy");
							try {
								caducitat = sdf.parse(dataCaducitat);
								correcte3 = true;
							} catch (ParseException e) {
								System.out.println("[Error]La data no segueix el format mm/aaaa.");
							}
		        		}
		        	
					} catch (ClientNoExisteix e) {
						System.out.println("[Error]" + e.getMessage());
						op = 4;
					}
		        		break;
		        	case 6:
					try {
						cURH.pagament(targeta, caducitat);
						System.out.println("LA RESERVA SHA REALITZAT AMB EXIT!");
						System.out.println("Esciu 0 per fer una altra reserva, o quelcom diferent per a sortir del programa.");
						Scanner scanner = new Scanner(System.in);
						String opcio = scanner.nextLine();
						int escollit;
						try {
							escollit = Integer.parseInt(opcio);
							if(escollit == 0) op = 0;
							else sortir = true;
						} catch (NumberFormatException e) {
							sortir = true;
						} 				
						
					} catch (ServeiNoDisponible e) {
						System.out.println("[Error]" + e.getMessage());
						op = 5;
					} catch (ClientNoExisteix e) {
						System.out.println("[Error]" + e.getMessage());
					} catch (HabitacioNoExisteix e) {
						System.out.println("[Error]" + e.getMessage());
					}
		        		break;
		        	default:
		        		System.out.println("oooooopppppssss");
		        		sortir = true;
		        		break;
		        }  
	        }
	        
//#############################################################################################	
			tx.commit();
		}
		catch (RuntimeException e) {
			tx.rollback();
			throw e;
		}
		finally {
			HibernateUtil.getSessionFactory().close();
		}
		
	}
	
	private static Set<String> poblacions;
	private static String poblacio;
	private static Date dIni;
	private static Date dFi;
	private static int numOcup;
	private static Map<String, Object> hotel;
	private static String tipusHab;
	private static String nomHotel;
	private static String dni;
	private static String targeta;
	private static Date caducitat;

}
